# Libuv Prepare句柄 结合libuv的事件循环过程,在每个循环周期会执行 `uv__run_prepare()`函数 ,如下图: ![](media/image-20211205152347408.png) 注意:Run prepare handles 在idle之后,io之前, prepare handles和idle 基本一样,差别在于: ## Demo ```c #include #include #include int64_t num = 0; void idle_cb(uv_idle_t* handle) { num++; printf("idle callback\n"); if (num >= 5) { printf("idle stop, num = %ld\n", num); uv_stop(uv_default_loop()); } } void prep_cb(uv_prepare_t *handle) { printf("prep callback\n"); } int main() { uv_idle_t idler; uv_prepare_t prep; uv_idle_init(uv_default_loop(), &idler); uv_idle_start(&idler, idle_cb); uv_prepare_init(uv_default_loop(), &prep); uv_prepare_start(&prep,prep_cb); uv_run(uv_default_loop(), UV_RUN_DEFAULT); return 0; } ``` 执行结果: ``` idle callback prep callback idle callback prep callback idle callback prep callback idle callback prep callback idle callback idle stop, num = 5 prep callback ``` ## 空闲句柄的API函数 - 初始化句柄 ```c int uv_prepare_init(uv_loop_t* loop, uv_prepare_t* prepare) ``` - 设置回调函数 ```c int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb) ``` - 停止 ```c int uv_prepare_stop(uv_prepare_t* prepare) ``` 同`uv_idle_init`这个函数的话,是找不到它的具体源码如下: src\unix\loop-watcher.c文件内容 ```c #include "uv.h" #include "internal.h" #define UV_LOOP_WATCHER_DEFINE(name, type) \ int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \ uv__handle_init(loop, (uv_handle_t*)handle, UV_##type); \ handle->name##_cb = NULL; \ return 0; \ } \ \ int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \ if (uv__is_active(handle)) return 0; \ if (cb == NULL) return UV_EINVAL; \ QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \ handle->name##_cb = cb; \ uv__handle_start(handle); \ return 0; \ } \ \ int uv_##name##_stop(uv_##name##_t* handle) { \ if (!uv__is_active(handle)) return 0; \ QUEUE_REMOVE(&handle->queue); \ uv__handle_stop(handle); \ return 0; \ } \ \ void uv__run_##name(uv_loop_t* loop) { \ uv_##name##_t* h; \ QUEUE queue; \ QUEUE* q; \ QUEUE_MOVE(&loop->name##_handles, &queue); \ while (!QUEUE_EMPTY(&queue)) { \ q = QUEUE_HEAD(&queue); \ h = QUEUE_DATA(q, uv_##name##_t, queue); \ QUEUE_REMOVE(q); \ QUEUE_INSERT_TAIL(&loop->name##_handles, q); \ h->name##_cb(h); \ } \ } \ \ void uv__##name##_close(uv_##name##_t* handle) { \ uv_##name##_stop(handle); \ } UV_LOOP_WATCHER_DEFINE(prepare, PREPARE) UV_LOOP_WATCHER_DEFINE(check, CHECK) UV_LOOP_WATCHER_DEFINE(idle, IDLE) ``` 针对prepare handle 宏定义展开后如下: ```c int uv_prepare_init(uv_loop_t* loop, uv_prepare_t* handle) { /* 初始化handle的类型,所属loop,设置UV_HANDLE_REF标志,并且把handle插入loop->handle_queue队列的队尾 */ uv__handle_init(loop, (uv_handle_t*)handle, UV_IDLE); handle->prepare_cb = NULL; return 0; } int uv_prepare_start(uv_prepare_t* handle, uv_prepare_cb cb) { /* 如果已经执行过start函数则直接返回 */ if (uv__is_active(handle)) return 0; /* 回调函数不允许为空 */ if (cb == NULL) return UV_EINVAL; /* 把handle插入loop中prepare_handles队列,loop有prepare,prepare和check三个队列 */ QUEUE_INSERT_HEAD(&handle->loop->prepare_handles, &handle->queue); /* 指定回调函数,在事件循环迭代的时候被执行 */ handle->prepare_cb = cb; /* 启动prepare handle,设置UV_HANDLE_ACTIVE标记并且将loop中的handle的active计数加一, init的时候只是把handle挂载到loop,start的时候handle才处于激活态 */ uv__handle_start(handle); return 0; } int uv_prepare_stop(uv_prepare_t* handle) { /* 如果prepare handle没有被启动则直接返回 */ if (!uv__is_active(handle)) return 0; /* 把handle从loop中相应的队列移除,但是还挂载到handle_queue中 */ QUEUE_REMOVE(&handle->queue); /* 清除UV_HANDLE_ACTIVE标记并且减去loop中handle的active计数 */ uv__handle_stop(handle); return 0; } /* 在每一轮循环中执行该函数,具体见uv_run */ void uv__run_prepare(uv_loop_t* loop) { uv_prepare_t* h; QUEUE queue; QUEUE* q; /* 把loop的prepare_handles队列中所有节点摘下来挂载到queue变量 */ QUEUE_MOVE(&loop->prepare_handles, &queue); /* while循环遍历队列,执行每个节点里面的函数 */ while (!QUEUE_EMPTY(&queue)) { /* 取下当前待处理的节点 */ q = QUEUE_HEAD(&queue); /* 取得该节点对应的整个结构体的基地址 */ h = QUEUE_DATA(q, uv_prepare_t, queue); /* 把该节点移出当前队列 */ QUEUE_REMOVE(q); /* 重新插入loop->prepare_handles队列 */ QUEUE_INSERT_TAIL(&loop->prepare_handles, q); /* 执行对应的回调函数 */ h->prepare_cb(h); } } /* 关闭这个prepare handle */ void uv__prepare_close(uv_prepare_t* handle) { uv_prepare_stop(handle); } ```